/*************************************************************************************************
 *
 *                                  MODBUS带参数配置数据处理模块
 *
 **************************************************************************************************/

package com.cofdet.modbusdebugger;

import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.charset.Charset;

public class ModbusCfg {
    public boolean isAddAdr = true;           //是否增加地址前缀
    public boolean isAddFunCode = true;       //是否增加功能码
    public boolean isAddSubFunCode = true;    //是否增加子功能码
    public boolean isAddCRC = true;           //是否增加CRC校验
    public boolean isAddLRC = false;           //是否增加LRC校验
    public boolean isAscMode = false;          //Asc编码模式
    public boolean isAscAffix = false;          //Asc前后缀
    public boolean isHexSend = false;          //Hex模式发送
    public boolean isHexRcv = false;          //Hex模式接收
    public boolean isRcvDispAll = false;      //是否接收全显示

    public int ModbusAdr  = 1;                 //Modbus通讯地址
    public int FunCode  = 62;                  //功能码
    public int SubFunCode = 0;                //子功能码

    /**
     * 带配置MODBUS发送处理函数
     * @param ByteBuffer wrBuf等追加写入的空缓冲
     * @param final String msg 待转换的原始字符
     */
    public final void SendPro(ByteBuffer wrBuf, final String msg)
    {
        //这里将用户Msg转换为通讯数据(增加前后缀)
        if(isAddAdr) wrBuf.put((byte)ModbusAdr);//插入地址
        if(isAddFunCode) wrBuf.put((byte)FunCode);//插入功能码
        if(isAddSubFunCode) wrBuf.put((byte)SubFunCode);//插入子功能码

        if (isHexSend) //十六进制方式输入了
            HexStrByte.HexStr2Byte(msg, wrBuf);
        else {
            try{
                wrBuf.put(ByteBuffer.wrap(msg.getBytes("GBK")));//转码为GBK插入
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

        wrBuf.flip(); //需要重头读数据了
        if(isAddCRC) {//增加校验
            int Len = wrBuf.limit();
            wrBuf.limit(Len + 2);
            int CRC = ModbusNetData.GetCRC16(wrBuf.array(), Len);
            wrBuf.put(Len, (byte)(CRC / 256));//CRC高位
            wrBuf.put(Len + 1, (byte)(CRC % 256));//CRC低位
        }
        if(isAddLRC) {//增加LRC校验
            int Len = wrBuf.limit();
            wrBuf.limit(Len + 1);
            int LRC = ModbusNetData.GetLRC(wrBuf.array(),  Len);
            wrBuf.put(Len, (byte)(LRC));
        }
        if(isAscMode) {//asc模式时编码
            int Len = wrBuf.limit();
            Len = ModbusNetData.DataToASC(wrBuf.array(), wrBuf.array(), 1, Len);
            wrBuf.limit(Len); //变更长度,含首尾附加
        }
        if(isAscAffix) {//asc前后缀
            int Len = wrBuf.limit();
            wrBuf.limit(Len + 3); //变更长度,含首尾附加
            wrBuf.put(0, (byte)0x3a);//编码自动增加前缀":"
            wrBuf.put(Len + 1, (byte)0x0d);//后缀回车
            wrBuf.put(Len + 2, (byte)0x0a);//后缀换行
        }
    }

    /**
     * 带配置MODBUS接收处理函数
     * @param ByteBuffer wrBuf等追加写入的空缓冲
     * @param final String msg 待转换的原始字符
     */
    public final String RcvPro(byte buff[], int rcvLen)
    {
        String rcvMsg;
        int Offset = 0; //起始位置
        rcvMsg = null;
        //没有全接收时
        if(isRcvDispAll == false) {
            int MinRcv = 0; //接收长度判断
            if (isAddAdr) Offset++;     //需地址返回
            if (isAddFunCode) Offset++; //需功能码返回(错误时最高位置1)
            MinRcv = Offset;
            if (isAddSubFunCode) Offset++; //去子功能码
            if(isAscMode) MinRcv *= 2; //asc模式时解码需大一倍
            if(isAscAffix) MinRcv+= 3; //asc前后缀增加3个
            //预检查与处理
            if (rcvLen < MinRcv) //接收长度检查
                rcvMsg = "Err1: 接收数据过短";
            else{
                if(isAscAffix) {//去asc前后缀
                    if(buff[0] != (byte)0x3a) rcvMsg = "Err1: LRC前缀错误";
                    else{//对了
                        rcvLen -= 3;//去前后缀,暂不对后缀进行检查
                        System.arraycopy(buff, 1, buff, 0, rcvLen);
                    }
                }
            }
            if(rcvMsg == null) {//数据无误时
                if(isAscMode) {//asc模式时解码
                    rcvLen = ModbusNetData.AscToData(buff, buff, rcvLen);
                }
                if(isAddCRC) {//CRC检查
                    rcvLen -= 2;
                    int CRC = ModbusNetData.GetCRC16(buff, rcvLen);
                    if (CRC != (((buff[rcvLen] & 0Xff) << 8) | (buff[rcvLen + 1] & 0Xff))) {
                        rcvMsg = "Err1: CRC校验错误";
                    }
                }else if (isAddLRC) {//LRC检查
                    rcvLen -= 1;
                    byte LRC = ModbusNetData.GetLRC(buff, rcvLen);
                    if (LRC != buff[rcvLen]) {
                        rcvMsg = "Err1: LRC校验错误";
                    }
                }
            }
        }

        if(rcvMsg == null) {//数据无误时
            rcvLen -= Offset; //最后去除不需显示的数
            if (isHexRcv) {//直接转换为十六进制显示
                rcvMsg = HexStrByte.Byte2HexStr(buff, Offset, rcvLen).toString();
            }
            else {//将转换完成的内容转换为字符送至前端字符标准
                ByteBuffer buf = ByteBuffer.wrap(buff, Offset, rcvLen);
                Charset inCharset = Charset.forName("GBK");
                rcvMsg = inCharset.decode(buf).toString();
            }
        }
        return rcvMsg;
    }
}